/////////////////////////////////////////////////////////////////////////////
//
// (c) 2007 BinaryComponents Ltd.  All Rights Reserved.
//
// http://www.binarycomponents.com/
//
/////////////////////////////////////////////////////////////////////////////

using SuperListEx.Utility.Collections;

namespace SuperListEx
{
  public class ColumnList : EventingList<Column>
  {
    #region vars
    private readonly EventingList<Column> _visibleItems = new EventingList<Column>();
    private readonly EventingList<Column> _groupedItems = new EventingList<Column>();
    private bool _inColumnsChanged = false;
    #endregion

    #region events
    public event ColumnDataChangedHandler ColumnDataChanged;
    #endregion

    #region constructor
    public ColumnList()
    {
      DataChanged += ColumnList_DataChanged;
      GroupedItems.DataChanged += GroupedItems_DataChanged;
      VisibleItems.DataChanged += VisibleItems_DataChanged;

      _visibleItems.AllowsDuplicates = false;
    }
    #endregion

    #region properties
    public ListControl Parent
    {
      get;
      set;
    }

    public EventingList<Column> GroupedItems
    {
      get
      {
        return _groupedItems;
      }
    }

    public EventingList<Column> VisibleItems
    {
      get
      {
        return _visibleItems;
      }
    }

    public Column FromName(string name)
    {
      foreach (Column c in this)
      {
        if (c.Name == name)
        {
          return c;
        }
      }
      return null;
    }
    #endregion

    #region Implementation
    protected virtual void OnColumnDataChanged(ColumnDataChangedEventArgs eventArgs)
    {
      if (ColumnDataChanged != null) ColumnDataChanged(this, eventArgs);
    }

    private void ColumnList_DataChanged(object sender, EventInfo<Column> e)
    {
      _inColumnsChanged = true;

      try
      {
        switch (e.EventType)
        {
          case EventType.Deleted:
            _visibleItems.RemoveRange(e.Items);
            _groupedItems.RemoveRange(e.Items);
            foreach (Column c in e.Items)
            {
              c.DataChanged -= column_DataChanged;
            }
            break;
          case EventType.Added:
            foreach (Column c in e.Items)
            {
              if (c.IsVisible && _visibleItems.IndexOf(c) == -1)
              {
                _visibleItems.Add(c);
              }
              if (c.IsGrouped && _groupedItems.IndexOf(c) == -1)
              {
                _groupedItems.Add(c);
              }
              c.DataChanged += column_DataChanged;
              c.Parent = this.Parent;
            }
            break;
          default:
            break;
        }
      }
      finally
      {
        _inColumnsChanged = false;
      }
    }

    private void column_DataChanged(object sender, ColumnDataChangedEventArgs e)
    {
      OnColumnDataChanged(e);

      if (_inColumnsChanged)
      {
        return;
      }
      _inColumnsChanged = true;
      try
      {
        switch (e.WhatChanged)
        {
          case WhatPropertyChanged.IsGroup:
            if (e.Column.IsGrouped)
            {
              _groupedItems.Add(e.Column);
            }
            else
            {
              _groupedItems.Remove(e.Column);
            }
            break;
          case WhatPropertyChanged.IsVisible:
            if (e.Column.IsVisible)
            {
              _visibleItems.Add(e.Column);
            }
            else
            {
              _visibleItems.Remove(e.Column);
            }
            break;
        }
      }
      finally
      {
        _inColumnsChanged = false;
      }
    }

    private void VisibleItems_DataChanged(object sender, EventInfo<Column> e)
    {
      if (_inColumnsChanged)
      {
        return;
      }
      _inColumnsChanged = true;
      try
      {
        switch (e.EventType)
        {
          case EventType.Deleted:
            foreach (Column c in e.Items)
            {
              c.IsVisible = false;
            }
            break;
          case EventType.Added:
            foreach (Column c in e.Items)
            {
              c.IsVisible = true;
              if (c.MoveBehaviour == MoveToGroupBehaviour.Move)
              {
                c.IsGrouped = false;
                _groupedItems.Remove(c);
              }
              if (IndexOf(c) == -1)
              {
                Add(c);
                c.ColumnHeaderIndex = IndexOf(c);
                c.Parent = this.Parent;
              }
            }
            break;
          default:
            break;
        }
      }
      finally
      {
        _inColumnsChanged = false;
      }
    }

    private void GroupedItems_DataChanged(object sender, EventInfo<Column> e)
    {
      if (_inColumnsChanged)
      {
        return;
      }
      _inColumnsChanged = true;
      try
      {
        switch (e.EventType)
        {
          case EventType.Deleted:
            foreach (Column c in e.Items)
            {
              c.IsGrouped = false;
            }
            break;
          case EventType.Added:
            foreach (Column c in e.Items)
            {
              c.IsGrouped = true;
              if (c.MoveBehaviour == MoveToGroupBehaviour.Move)
              {
                c.IsVisible = false;
                _visibleItems.Remove(c);
              }
              if (IndexOf(c) == -1)
              {
                Add(c);
              }
            }
            break;
          default:
            break;
        }
      }
      finally
      {
        _inColumnsChanged = false;
      }
    }

    public override void Clear()
    {
      base.Clear();
      _visibleItems.Clear();
      _groupedItems.Clear();
    }
    #endregion
  }
}